Option Explicit

Private Const HASH_CODE_RANDOM_SIZE As Integer = 15

'################################################################
' Descriptor
' Scripting.Dictionary 对象的替代品
'################################################################

'################################################################
' Field
'################################################################
' 保存所有的 key
' Map<key, VarPtr>
Private ks As Object

' 保存所有的 key
' Map<String, VarPair>
Private entries As Collection

'#######################################
' Constructor
'#######################################
Private Sub Class_Initialize()
    Set ks = UtilsCreateSysObj.createMap
    Set entries = New Collection
End Sub

Private Sub Class_Terminate()
    Set ks = Nothing
    Set entries = Nothing
End Sub

'################################################################
' Function
'################################################################
' 获取指定 key 下的数据
' @param k key
Public Function Item(ByRef k As Variant) As Variant
    If ks.Exists(k) Then
        ' 获取 key 对应的指针，然后获取 Entry
        Dim e As VarPair
        Set e = entries(ks.Item(k))
On Error GoTo catch
        Item = e.Key2
        GoTo continue
catch:
        Set Item = e.Key2
continue:
    End If
End Function

' 添加一个键值对
' @param k key
' @param v value
Public Sub Add(ByRef k As Variant, ByRef v As Variant)
    ' 检查内部是否存在指定的 key
    Dim e As VarPair
    If ks.Exists(k) Then
        ' 如果 key 已经存在了，则取出 VarPair 并修改 value
        Set e = entries(ks.Item(k))
        e.Key2 = v
    Else
        ' 如果不存在指定的 key，则创建一个新的 VarPair 并保存
        Set e = New VarPair
        e.Key1 = k
        e.Key2 = v

        ' 计算随机值作为 hashcode
        Dim hashCodeStr As String
        hashCodeStr = UtilsRandom.enNumStr(HASH_CODE_RANDOM_SIZE)

'-------------
        ' 防止碰撞
whileStart:
        While True
On Error GoTo catch
            ' 如发生碰撞（能够从顺序缓存中获取到），则生成一个新的 hash 值
            entries.Item hashCodeStr
            hashCodeStr = UtilsRandom.enNumStr(HASH_CODE_RANDOM_SIZE)
            Goto whileStart
catch:
            Err.Clear
            Resume whileEnd
        Wend
whileEnd:
'-------------

        ks.Add k, hashCodeStr
        entries.Add e, hashCodeStr
    End If
End Sub

' 检查指定 key 是否在当前 Map 中
Public Function Exists(ByRef k As Variant) As Boolean
    Exists = ks.Exists(k)
End Function

' 返回 Map 中所有 value 的数组
Public Function Items() As Variant()
    Dim result() As Variant

    If entries.count = 0 Then
        ReDim result(0 To 0)
    Else
        ReDim result(0 To entries.count - 1)

        Dim i As Integer
        Dim e As VarPair
        For i = 0 To entries.count - 1
            Set e = entries.Item(i + 1)
On Error GoTo catch
            result(i) = e.Key2
            GoTo continue
catch:
            Err.Clear
            Set result(i) = e.Key2
            Resume continue
continue:
        Next
    End If

    Items = result
End Function

' 返回 Map 中所有 key 的数组
Public Function Keys() As Variant()
    Keys = ks.Keys
End Function

' 从 Map 中删除指定的 key 及其对应的键值对对象
Public Sub Remove(ByRef k As Variant)
    If ks.Exists(k) Then
        entries.Remove ks.Item(k)
        ks.Remove k
    End If
End Sub

' 清空当前 Map 中缓存的所有内容
Public Sub RemoveAll()
    ks.RemoveAll
    UtilsCollection.removeAllCollection entries
End Sub

' 返回当前 map 中保存的键值对数量
Public Function Count() As Integer
    Count = ks.count
End Function